﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace GameNodeWithHandler
{
    class GameLogic
    {
        Random rnd;
        Drawer dr = new Drawer('#');
        GameField field = new GameField(6, 12, 10, 10); //размер поля HWXY
        private char snakeSymbol = '*';
        public ConsoleNode targetNode;
        public List<ConsoleNode> nodes;
        private int winCounts;
        InputHandler _ih;
        DynamicMovement directionForMovement = DynamicMovement.Field;
        private int countOfLifes = 3;
        private int speed = 500;
        private byte levelCount = 1;

        public GameLogic()
        {
            rnd = new Random();
            nodes = new List<ConsoleNode>();
            FillListOfNodes(3);

            targetNode = GenerateTargetNode();
            _ih = new InputHandler();
            _ih.KeyLeft += ChangeDirectionToLeft;
            _ih.KeyRight += ChangeDirectionToRight;
            _ih.KeyUp += ChangeDirectionToUp;
            _ih.KeyDown += ChangeDirectionToDown;
            _ih.PauseButtom += StopTheGame;
        }
        public void FillListOfNodes(int amountOfNodes)
        {
            //-4 чтобы по-любому поместилась инишиал змея в 3 элемента
            nodes.Add(new ConsoleNode(rnd.Next(field.StartX, field.StartX + field.Width - 1), rnd.Next(field.StartY, field.StartY + field.Height - 4), snakeSymbol, ConsoleColor.DarkGray));
            for (int i = 1; i < amountOfNodes; i++)
            {
                nodes.Add(new ConsoleNode(nodes[i-1].X, nodes[i-1].Y+1, snakeSymbol, ConsoleColor.DarkYellow));
            }
        }

        public ConsoleNode GenerateTargetNode()
        {
            bool done = false;
            int newNodeX;
            int newNodeY;
            do
            {
                newNodeX = rnd.Next(field.StartX, field.StartX + field.Width - 1);
                newNodeY = rnd.Next(field.StartY, field.StartY + field.Height - 1);
                if (!IsOnNode(newNodeX, newNodeY))
                {
                    done = true;
                }
            }
            while (done == false);
            return new ConsoleNode(newNodeX, newNodeY, '*', ConsoleColor.Red);
        }

        public void StartGame()
        {
            bool gameOver = false;
            do
            {
                bool isNewRound = false;
                do
                {
                    dr.DrawListAndScore(nodes, field, winCounts, levelCount, countOfLifes);
                    dr.DraweGameFieldFrame(field);
                    //
                    _ih.QueryKB();
                    EndlessMovement();
                    //
                    dr.DrawGameNode(targetNode);
                    //
                    foreach (var gameNode in nodes)
                    {
                        dr.DrawGameNode(gameNode);
                    }
                    if (targetNode.Y == nodes[0].Y && targetNode.X == nodes[0].X)
                    {
                        targetNode = GenerateTargetNode();
                        dr.DrawGameNode(targetNode);

                        IncrementSnake();
                        winCounts++;
                        if (winCounts % 5 == 0)
                        {
                            speed -= 50;
                            levelCount++;
                            if (levelCount%10 == 0)
                            {
                                speed = 500;
                            }
                        }
                        isNewRound = true;
                    }
                    Thread.Sleep(speed);
                    if (countOfLifes == 0)
                    {
                        dr.DrawGameOver(field);
                        isNewRound = true;
                        gameOver = true;
                    }
                }
                while (!isNewRound);
            }
            while (!gameOver);
        }

        private void IncrementSnake()
        {
            switch (directionForMovement)
            {
                case DynamicMovement.Down:
                    {
                        if (IsOnField(nodes[0].X, nodes[0].Y+1))
                        {
                            nodes.Add(new ConsoleNode(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y, nodes[nodes.Count - 1].Symbol, nodes[nodes.Count - 1].NodeColor));
                            for (int i = nodes.Count - 1; i > 1; i--)
                            {
                                nodes[i].X = nodes[i-1].X;
                                nodes[i].Y = nodes[i-1].Y;
                            }
                        }
                        break;
                    }
                case DynamicMovement.Up:
                    {
                        if (IsOnField(nodes[0].X, nodes[0].Y-1))
                        {
                            nodes.Add(new ConsoleNode(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y, nodes[nodes.Count - 1].Symbol, nodes[nodes.Count - 1].NodeColor));
                            for (int i = nodes.Count - 1; i > 1; i--)
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                        }
                        break;
                    }
                case DynamicMovement.Left:
                    {
                        if (IsOnField(nodes[0].X-1, nodes[0].Y))
                        {
                            nodes.Add(new ConsoleNode(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y, nodes[nodes.Count - 1].Symbol, nodes[nodes.Count - 1].NodeColor));
                            for (int i = nodes.Count - 1; i > 1; i--)
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                        }
                        break;
                    }
                case DynamicMovement.Right:
                    {
                        if (IsOnField(nodes[0].X+1, nodes[0].Y))
                        {
                            nodes.Add(new ConsoleNode(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y, nodes[nodes.Count - 1].Symbol, nodes[nodes.Count - 1].NodeColor));
                            for (int i = nodes.Count - 1; i > 1; i--)
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                        }
                        break;
                    }
            }
        }

        public bool IsOnField(int nodeX, int nodeY)
        {
            if (nodeX <= field.StartX + field.Width - 1 && nodeX >= field.StartX && nodeY >= field.StartY && nodeY <= field.StartY + field.Height - 1)
            {
                return true;
            }
            return false;
        }

        public bool IsOnNode(int nodeX, int nodeY)
        {
            foreach (var everyGameNode in nodes)
            {
                if (nodeY == everyGameNode.Y && nodeX == everyGameNode.X)
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsEndlessMovementPossible(int nodeX, int nodeY)
        {
            if (!IsOnNode(nodeX, nodeY) && IsOnField(nodeX, nodeY))
            {
                return true;
            }
            return false;
        }

        private void EndlessMovement()
        {
            switch (directionForMovement)
            {

                case DynamicMovement.Down:
                    {
                        if (IsEndlessMovementPossible(nodes[0].X, nodes[0].Y + 1))
                        {
                            for (int i = nodes.Count - 1; i >= 1; i--)  //добавить метод для проверки выхода на рамку и делать gameOver=true DONE
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                            nodes[0].MoveDown();
                        }
                        else
                        {
                            countOfLifes--;
                        }
                        break;
                    }
                case DynamicMovement.Up:
                    {
                        if (IsEndlessMovementPossible(nodes[0].X, nodes[0].Y - 1))
                        {
                            for (int i = nodes.Count - 1; i >= 1; i--)
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                            nodes[0].MoveUp();
                        }
                        else
                        {
                            countOfLifes--;
                        }
                        break;
                    }
                case DynamicMovement.Left:
                    {
                        if (IsEndlessMovementPossible(nodes[0].X - 1, nodes[0].Y))
                        {
                            for (int i = nodes.Count - 1; i >= 1; i--)
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                            nodes[0].MoveLeft();
                        }
                        else
                        {
                            countOfLifes--;
                        }
                        break;
                    }
                case DynamicMovement.Right:
                    {
                        if (IsEndlessMovementPossible(nodes[0].X + 1, nodes[0].Y))
                        {
                            for (int i = nodes.Count - 1; i >= 1; i--)
                            {
                                nodes[i].X = nodes[i - 1].X;
                                nodes[i].Y = nodes[i - 1].Y;
                            }
                            nodes[0].MoveRight();
                        }
                        else
                        {
                            countOfLifes--;
                        }
                        break;
                    }
            }

        }

        private void ChangeDirectionToLeft(object sender, EventArgs e)
        {
            if (IsEndlessMovementPossible(nodes[0].X - 1, nodes[0].Y))
            {
                directionForMovement = DynamicMovement.Left;
            }
            else           
                countOfLifes--;
        }

        private void ChangeDirectionToRight(object sender, EventArgs e)
        {
            if (IsEndlessMovementPossible(nodes[0].X + 1, nodes[0].Y))
            {
                directionForMovement = DynamicMovement.Right;
            }
            else
                countOfLifes--;
        }

        private void ChangeDirectionToUp(object sender, EventArgs e)
        {
            if (IsEndlessMovementPossible(nodes[0].X, nodes[0].Y - 1)  )
            {
                directionForMovement = DynamicMovement.Up;
            }
            else
                countOfLifes--;
        }

        private void ChangeDirectionToDown(object sender, EventArgs e)
        {
            if (IsEndlessMovementPossible(nodes[0].X, nodes[0].Y + 1) )
            {
                directionForMovement = DynamicMovement.Down;
            }
            else
                countOfLifes--;
        }

        private void StopTheGame(object sender, EventArgs e)
        {
            Console.ReadKey();
        }
    }
}
    enum Position
    {
        Node,
        Free,
        Border
    }
    enum DynamicMovement
{
    Up,
    Down,
    Left,
    Right,
    Field
}